﻿#region Header

// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------

#endregion

#region Usings

using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Text;
using System.Reflection;
using ScrumTable.Common.Logging;

#endregion

namespace ScrumTable.Common.FileSystem
{
    /// <summary>
    /// Represents an utility class for the .NET Directory class.
    /// </summary>
    public static class DirectoryUtil
    {
        #region Declarations

        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------

        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------
        
        #endregion

        #region Constructors / Destructor

        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------

        #endregion

        #region Methods

        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------

        /// <summary>
        /// Creates the specified folder and returns true if the requested action
        /// could be completed.
        /// </summary>
        /// <param name="toCreate">Specifies the path of the directory to create.</param>
        /// <returns>Returns true if the directory exists after the creation.</returns>
        public static bool TryCreate(string toCreate)
        {
            if (!string.IsNullOrEmpty(toCreate)) { return false; }
            
            DirectoryInfo directory = null;

            try { directory = new DirectoryInfo(toCreate); }
            catch { return false; }

            if (!directory.Exists)
            {
                try
                {
                    directory.Create();
                }
                catch (IOException)
                {
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// Ensures that the specified folder exists or throws an exception if it could not be created.
        /// </summary>
        /// <param name="toEnsure">Specifies the path of the directory to create if it does not exist.</param>
        /// <returns>Returns the directory info of the given path.</returns>
        public static void EnsureExists(this DirectoryInfo toEnsure)
        {
            PreCondition.AssertNotNull(toEnsure, "toEnsure");

            if (!toEnsure.Exists)
            {
                toEnsure.Create();
            }
        }

        /// <summary>
        /// Ensures that the specified folder exists or throws an exception if it could not be created.
        /// </summary>
        /// <param name="path">Specifies the path of the directory to create if it does not exist.</param>
        /// <returns>Returns the directory info of the given path.</returns>
        public static DirectoryInfo EnsureExists(string path)
        {
            PreCondition.AssertNotNullOrEmpty("path", path);

            DirectoryInfo directory = new DirectoryInfo(path);
            directory.EnsureExists();
            return directory;
        }

        /// <summary>
        /// Ensures that the specified folder exists. Takes the given source path as default
        /// data set.
        /// </summary>
        /// <param name="path">Specifies the path of the directory to create if it does not exist.</param>
        /// <param name="sourcePath">Specifies the path of the directory with the original data to create if it does not exist.</param>
        /// <returns>Returns the directory info of the given path.</returns>
        public static DirectoryInfo EnsureExistsFrom(string path, string sourcePath)
        {
            PreCondition.AssertNotNullOrEmpty("path", path);

            return EnsureExistsFrom(
                path,
                toEnsureExists =>
                    {
                        DirectoryInfo sourceDirectory = new DirectoryInfo(sourcePath);

                        if (sourceDirectory.Exists)
                        {
                            sourceDirectory.TryCopyDirectory(toEnsureExists, false);
                        }
                    });
        }

        /// <summary>
        /// Ensures that the specified folder exists. Takes the given source path as default
        /// data set.
        /// </summary>
        /// <param name="path">Specifies the path of the directory to create if it does not exist.</param>
        /// <param name="toExecuteIfNotExists">Specifies the action to execute if the directory does not exist.</param>
        /// <returns>Returns the directory info of the given path.</returns>
        public static DirectoryInfo EnsureExistsFrom(string path, Action<DirectoryInfo> toExecuteIfNotExists)
        {
            PreCondition.AssertNotNullOrEmpty("path", path);

            DirectoryInfo toEnsureExists = new DirectoryInfo(path);

            if (!toEnsureExists.Exists)
            {
                try
                {
                    toExecuteIfNotExists(toEnsureExists);
                }
                catch (Exception e)
                {
                    Logger.Warn(e.Message, e);
                }
                
                if (!toEnsureExists.Exists)
                {
                    toEnsureExists.Create();
                }
            }
            return toEnsureExists;
        }

        /// <summary>
        /// Tries to copy a folder structure from the given source to a destionation directory.
        /// </summary>
        /// <param name="source">Specifies the source directory to copy.</param>
        /// <param name="destination">Specifies the destination directory.</param>
        /// <param name="overwriteExisting">True to overwrite existing files.</param>
        /// <returns>Returns true if the copy process succeeded.</returns>
        public static bool TryCopyDirectory(this DirectoryInfo source, DirectoryInfo destination, bool overwriteExisting)
        {
            try
            {
                source.CopyDirectory(destination, overwriteExisting);
            }
            catch (Exception ex)
            {
                Logger.Warn(ex);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Copies a folder structure from the given source to a destionation directory.
        /// An exception will be thrown if the copy process failed.
        /// </summary>
        /// <param name="source">Specifies the source directory to copy.</param>
        /// <param name="destination">Specifies the destination directory.</param>
        /// <param name="overwriteExisting">True to overwrite existing files.</param>
        public static void CopyDirectory(this DirectoryInfo source, DirectoryInfo destination, bool overwriteExisting)
        {
            PreCondition.AssertNotNull(source, "source");
            PreCondition.AssertNotNull(destination, "destination");

            if (source.Exists)
            {
                destination.EnsureExists();

                foreach (FileInfo toCopy in source.GetFiles())
                {
                    toCopy.CopyTo(Path.Combine(destination.FullName, toCopy.Name), overwriteExisting);
                }

                foreach (DirectoryInfo toCopy in source.GetDirectories())
                {
                    toCopy.CopyDirectory(
                        new DirectoryInfo(Path.Combine(destination.FullName, toCopy.Name)),
                        overwriteExisting);
                }
            }
        }


        #endregion

        #region Events

        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        #endregion
    }
}